//! Simple behavior to make the block fall when it notices that there's an air
//! block below it.  This replicates classic-style sand/gravel.

use craftdig_math::Direction;

use crate::block::BlockStateSnapshot;

use super::prelude::*;

pub struct FsPlaceBehavior;

impl MsgAccept for FsPlaceBehavior {
    type Msg = OnPlaceMessage;

    fn accept(&self, inst: &mut BlockContext, _msg: &Self::Msg) -> Result<(), BehaviorError> {
        do_fall_check(inst)
    }
}

pub struct FsUpdateBehavior;

impl MsgAccept for FsUpdateBehavior {
    type Msg = NeighborUpdateMessage;

    fn accept(&self, inst: &mut BlockContext, _msg: &Self::Msg) -> Result<(), BehaviorError> {
        do_fall_check(inst)
    }
}

fn do_fall_check(inst: &mut BlockContext) -> Result<(), BehaviorError> {
    let below_id = inst
        .get_neighbor_blkid(Direction::Down)
        .unwrap_or(block::BlkId::zero());

    if below_id.is_zero() {
        let self_id = inst.get_self_blkid();

        let self_state = BlockStateSnapshot::new_simple(self_id);
        let air_state = BlockStateSnapshot::new_simple(block::BlkId::zero());

        inst.submit_block_change(inst.pos(), air_state);
        inst.submit_block_change(inst.pos().neighbor_to(Direction::Down), self_state);
    }

    Ok(())
}
